﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ITAP.ContourBuilder.Components;
using System.Windows.Forms;
using ITAP.ContourBuilder.GUI;

using ITAP.Core.Calculations;
using ITAP.Core.Modelling.Primitives;
using ITAP.Core.Modelling;

namespace ITAP.ContourBuilder.Operations
{
    public class OperationCreateCurve : Operation
    {
        public override void Execute()
        {
            int counter = 0;
            foreach (IContourComponent component in this.Control.ContourContainer.SelectedComponentsStack)
                if (component is ContourElement)
                    counter++;

            if (counter != 2)
            {
                MessageBox.Show("Невозможно создать фаску, т.к. нет подходящих выбранных элементов контура.");
                this.Cancel();
                return;
            }

            foreach (IContourComponent component in this.Control.ContourContainer.InnerComponents)
            {
                if (!(component is ContourModel))
                    continue;

                ContourModel model = component as ContourModel;
                ContourElement prevElement = null;
                ContourElement startElement = null;
                foreach (ContourElement element in model)
                {
                    if(startElement == null)
                    {
                        startElement = element;
                        prevElement = element;
                        continue;
                    }
                    if (element.StartConnectedComponent == prevElement.EndConnectedComponent && element.Selected && prevElement.Selected)
                        //&& element.SelectedPoint != ContourElementPoints.None && prevElement.SelectedPoint != ContourElementPoints.None)
                    {
                        if (element.Height != 0 || prevElement.Height != 0)
                        {
                            MessageBox.Show("Выбранные элементы не должны быть изогнутыми.");
                            this.Cancel();
                            return;
                        }
                        this.CreateFacet(prevElement, element);
                        break;
                    }
                    prevElement = element;
                }
                if (startElement.StartConnectedComponent == prevElement.EndConnectedComponent && startElement.Selected && prevElement.Selected)
                //&& startElement.SelectedPoint != ContourElementPoints.None && prevElement.SelectedPoint != ContourElementPoints.None)
                {
                    if (startElement.Height != 0 || prevElement.Height != 0)
                    {
                        MessageBox.Show("Выбранные элементы не должны быть изогнутыми.");
                        this.Cancel();
                        return;
                    }
                    this.CreateFacet(prevElement, startElement);
                    break;
                }
                else
                {
                    this.Cancel();
                    return;
                }
            }
        }

        private void CreateFacet(ContourElement prevElement, ContourElement element)
        {
            FormEnterCurve form = new FormEnterCurve();
            if(form.ShowDialog() != DialogResult.OK)
                this.Cancel();

            ModelVector prevVector = prevElement.Primitive.GetTangent(1).Rotate(new Angle(Math.PI));
            ModelVector vector = element.Primitive.GetTangent(0);
            Angle angle = ModelCalculations.GetAngleBetweenVectors(vector, prevVector, false);
            ModelVector middleVector = vector.Rotate(new Angle(angle.Value / 2));
            double H = (double)form.Radius / Math.Cos(Math.PI / 2 - angle.Value / 2);
            middleVector.Length = H;
            ModelPoint center = ModelCalculations.GetOffsetPoint(prevElement.EndPoint, middleVector);
            ModelVector vectorToStart = middleVector.Rotate(new Angle(-(Math.PI / 2 - angle.Value / 2)));
            ModelVector vectorToEnd = middleVector.Rotate(new Angle(Math.PI / 2 - angle.Value / 2));

            Line lineToStart = new Line(center, vectorToStart);
            Line lineToEnd = new Line(center, vectorToEnd);

            ModelPoint[] startPoints = prevElement.Primitive.Intersect(lineToStart, EndType.End);
            ModelPoint[] endPoints = element.Primitive.Intersect(lineToEnd, EndType.Start);

            ModelPoint startPoint = startPoints[0];
            ModelPoint endPoint = endPoints[0];

            middleVector.Length = H - (double)form.Radius;
            ModelPoint centerPoint = ModelCalculations.GetOffsetPoint(prevElement.EndPoint, middleVector);

            IContourComponent parent = element.StartConnectedComponent.Parent;
            IContourComponent connector = element.StartConnectedComponent;

            ContourConnectionProvider.Disconnect(prevElement, prevElement.EndConnectedComponent);
            ContourConnectionProvider.Disconnect(element, element.StartConnectedComponent);
            parent.RemoveInnerComponent(connector);

            ((IEndedPrimitive)prevElement.Primitive).EndPoint = startPoint.Clone() as ModelPoint;
            ((IEndedPrimitive)element.Primitive).StartPoint = endPoint.Clone() as ModelPoint;
            //prevElement.MoveEndPoint(startPoint);
            //element.MoveStartPoint(endPoint);

            Circle primitive = new Circle(startPoint, centerPoint, endPoint);
            ContourElement facet = ContourElementFactory.CreateContourElementFromPrimitive(primitive, "facet");
            element.GetRootModel().AddInnerComponent(facet);

            ContourConnector startConnector = ContourElementFactory.CreateConnector(facet.StartPoint);
            ContourConnector endConnector = ContourElementFactory.CreateConnector(facet.EndPoint);

            ContourConnectionProvider.Connect(prevElement, startConnector, EndType.End);
            ContourConnectionProvider.Connect(facet, startConnector, EndType.Start);
            ContourConnectionProvider.Connect(facet, endConnector, EndType.End);
            ContourConnectionProvider.Connect(element, endConnector, EndType.Start);

            element.GetRootModel().AddInnerComponent(startConnector);
            element.GetRootModel().AddInnerComponent(endConnector);

            this.Control.UpdateModel();
            this.Exit();
        }

        public override string ToString()
        {
            return "Создать изгиб";
        }

        public override bool CanUndo
        {
            get
            {
                return true;
            }
        }
    }
}
